﻿using Caliburn.Micro;
using SD.Common;
using SD.Infrastructure.DTOBase;
using SD.Infrastructure.WPF.Caliburn.Aspects;
using SD.Infrastructure.WPF.Caliburn.Base;
using SD.Infrastructure.WPF.Extensions;
using SD.IOC.Core.Mediators;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.ServiceModel.Extensions;
using System.Threading.Tasks;
using System.Windows;
using SlamDunk.MES.Client.ViewModels.Facility;
using SlamDunk.MES.IAppService.DTOs.Inputs;
using SlamDunk.MES.IAppService.DTOs.Outputs.ResourceContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.StockContext;
using SlamDunk.MES.IAppService.Interfaces;
using SlamDunk.MES.Presentation.Maps;
using SlamDunk.MES.Presentation.Models.NotifyModels;
using SlamDunk.ValueObjects.Enums;

namespace SlamDunk.MES.Client.ViewModels.StockInOrder
{
    /// <summary>
    /// 入库单据修改ViewModel
    /// </summary>
    public class UpdateViewModel : ScreenBase
    {
        #region # 字段及构造器

        /// <summary>
        /// 库存单据服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<IStockOrderContract> _iStockOrderContract;

        /// <summary>
        /// 资源定义服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<IResourceContract> _iResourceContract;

        /// <summary>
        /// 基础定义服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<IFoundationContract> _iFoundationContract;

        /// <summary>
        /// 编号生成服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<INumberContract> _iNumberContract;

        /// <summary>
        /// 窗口管理器
        /// </summary>
        private readonly IWindowManager _windowManager;

        /// <summary>
        /// 依赖注入构造器
        /// </summary>
        public UpdateViewModel(ServiceProxy<IStockOrderContract> iStockOrderContract, ServiceProxy<IResourceContract> iResourceContract, ServiceProxy<IFoundationContract> iFoundationContract, ServiceProxy<INumberContract> iNumberContract, IWindowManager windowManager)
        {
            _iStockOrderContract = iStockOrderContract;
            _iResourceContract = iResourceContract;
            _iFoundationContract = iFoundationContract;
            this._windowManager = windowManager;
            this._iNumberContract = iNumberContract;
        }

        #endregion

        #region 属性
        #region 单据编号
        /// <summary>
        /// 单据编号
        /// </summary>
        [DependencyProperty]
        public string Number { get; set; }
        #endregion

        #region 储存位置类型
        /// <summary>
        /// 储存位置类型
        /// </summary>
        [DependencyProperty]
        public IDictionary<string, string> StorageLocationTypes { get; set; }
        #endregion

        #region 库位列表
        /// <summary>
        /// 库位列表
        /// </summary>
        [DependencyProperty]
        public ObservableCollection<IdentiferNameNm> StorageLocations { get; set; }
        #endregion

        #region 源单据编号
        /// <summary>
        /// 源单据编号
        /// </summary>
        [DependencyProperty]
        public string SourceOrder { get; set; }
        #endregion

        #region 源单据Id
        /// <summary>
        /// 源单据Id
        /// </summary>
        [DependencyProperty]
        public string SourceOrderId { get; set; }
        #endregion

        #region 已选储存位置类型
        /// <summary>
        /// 已选储存位置类型
        /// </summary>
        [DependencyProperty]
        public StorageLocationType? SelectedStorageLocationType { get; set; }
        #endregion

        #region 已选库位列表
        /// <summary>
        /// 已选库位列表
        /// </summary>
        [DependencyProperty]
        public IdentiferNameNm SelectedStorageLocation { get; set; }
        #endregion

        #region 库位列表显示隐藏
        /// <summary>
        /// 库位列表显示隐藏
        /// </summary>
        [DependencyProperty]
        public Visibility StorageLocationComboBoxVisibility { get; set; }
        #endregion

        #region 库位描述显示隐藏
        /// <summary>
        /// 库位描述显示隐藏
        /// </summary>
        [DependencyProperty]
        public Visibility StorageLocationTextVisibility { get; set; }
        #endregion

        #region 库位描述
        /// <summary>
        /// 库位描述
        /// </summary>
        [DependencyProperty]
        public string StorageLocationText { get; set; }
        #endregion

        #region 源单据类型
        /// <summary>
        /// 源单据类型
        /// </summary>
        [DependencyProperty]
        public string SourceOrderType { get; set; }
        #endregion

        #region 已选单据类型列表
        /// <summary>
        /// 已选单据类型列表
        /// </summary>
        [DependencyProperty]
        public string StockOrderClass { get; set; }
        #endregion

        #region 描述
        /// <summary>
        /// 描述
        /// </summary>
        [DependencyProperty]
        public string Description { get; set; }
        #endregion

        #region 入库单据明细列表
        /// <summary>
        /// 入库单据明细集合
        /// </summary>
        [DependencyProperty]
        public ObservableCollection<StockInOrderDetailNm> DetailParams { get; set; }
        #endregion

        #region 入库单据
        /// <summary>
        /// 入库单据明细集合
        /// </summary>
        [DependencyProperty]
        public StockInOrderInfo _stockInOrderInfo { get; set; }
        #endregion

        #region 工厂模型名称
        /// <summary>
        /// 工厂模型名称
        /// </summary>
        [DependencyProperty]
        public string FacilityName { get; set; }
        #endregion

        #region 工厂模型Id
        /// <summary>
        /// 工厂模型Id
        /// </summary>
        [DependencyProperty]
        public Guid? FacilityId { get; set; }
        #endregion
        #endregion

        #region 方法
        #region 加载 —— async Task Load(StockInOrderInfo stockInOrderInfo)
        /// <summary>
        /// 加载
        /// </summary>
        public async Task Load(StockInOrderInfo stockInOrderInfo)
        {
            this._stockInOrderInfo = stockInOrderInfo;
            //初始化存储位置类型
            this.StorageLocationTypes = typeof(StorageLocationType).GetEnumMembers();
            //显示隐藏库位列表
            this.StorageLocationComboBoxVisibility = Visibility.Visible;
            this.StorageLocationTextVisibility = Visibility.Collapsed;

            if (stockInOrderInfo != null)
            {
                this.Busy();
                Number = stockInOrderInfo.Number;
                SelectedStorageLocationType = stockInOrderInfo.TargetStorageLocationType;
                await ReloadStorageLocation();
                SelectedStorageLocation = StorageLocations.Where(x => x.Id == Guid.Parse(stockInOrderInfo.TargetStorageLocationId)).FirstOrDefault();
                PageModel<StockOrderClassInfo> StockOrderClassInfos = await Task.Run(() => this._iStockOrderContract.Channel.GetStockOrderClassesByPage(null, StockDirectionType.Input, null, stockInOrderInfo.FacilityId, 1, int.MaxValue));
                this.StockOrderClass = StockOrderClassInfos.Datas.Where(x => x.Id == stockInOrderInfo.StockOrderClassId).FirstOrDefault().Name;
                if (stockInOrderInfo.SourceOrderType != null)
                {
                    this.SourceOrderType = EnumExtension.GetEnumMember(stockInOrderInfo.SourceOrderType);
                }
                this.SourceOrder = stockInOrderInfo.SourceOrderName;
                Description = stockInOrderInfo.Description;
                FacilityName = stockInOrderInfo.FacilityInfo?.Name;
                FacilityId = stockInOrderInfo.FacilityId;
                //加载入库单明细
                IEnumerable<StockOrderDetailInfo> StockInOrderInfos = await Task.Run(() => this._iStockOrderContract.Channel.GetStockOrderDetails(stockInOrderInfo.Id));
                DetailParams = new ObservableCollection<StockInOrderDetailNm>();
                foreach (var info in StockInOrderInfos)
                {
                    DetailParams.Add(new StockInOrderDetailNm(
                   info.MaterialId,
                   info.MaterialInfo.Name,
                   info.MaterialInfo.Number,
                   info.MaterialLotId,
                   info.Quantity,
                   info.Sort,
                   info.Description,
                   null,
                   info.MaterialLotInfo?.SupplierId,
                   info.MaterialLotInfo?.SupplierName,
                   info.MaterialLotInfo?.ProductionBatchNo,
                   info.MaterialLotInfo?.ProducedDate,
                   info.MaterialLotInfo?.GuaranteePeriod,
                   info.MaterialLotInfo?.ExpiredDate,
                   info.MaterialLotInfo?.ReceptionDate,
                   info.MaterialLotInfo?.Specification,
                   info.MaterialLotInfo?.MaterialSourceType,
                   null,
                   null,
                   false,
                   false,
                   null,
                   null,
                   info.MaterialInfo.StandardUnitNo
                   ));
                }
                this.Idle();
            }
        }
        #endregion

        #region 清空工厂模型 —— async void ClearFacility()
        /// <summary>
        /// 清空工厂模型
        /// </summary>
        public async void ClearFacility()
        {
            this.FacilityId = null;
            this.FacilityName = "";
        }
        #endregion

        #region 加载工厂模型-弹出层
        /// <summary>
        /// 加载工厂模型-弹出层
        /// </summary>
        public async void SelectFacility()
        {
            this.Busy();
            SelectFacilityViewModel viewModel = ResolveMediator.Resolve<SelectFacilityViewModel>();
            bool? result = await this._windowManager.ShowDialogAsync(viewModel);
            if (result == true)
            {
                FacilityId = viewModel.SelectedFacility.Id;
                FacilityName = viewModel.SelectedFacility.Name;
            }
            this.Idle();
        }
        #endregion

        #region 创建单据明细-弹出层 —— async void Create()
        /// <summary>
        /// 创建单据明细-弹出层
        /// </summary>
        public async void Create()
        {
            if (SelectedStorageLocationType == null)
            {
                MessageBox.Show("请选择储存位置类型！", "警告", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
            if (SelectedStorageLocation == null)
            {
                MessageBox.Show("请选择储存位置！", "警告", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
            AddItemViewModel viewModel = ResolveMediator.Resolve<AddItemViewModel>();
            viewModel.Load(FacilityId);
            bool? result = await this._windowManager.ShowDialogAsync(viewModel);
            if (result == true)
            {
                CreateDetailParam(
                   viewModel.SelectedMaterial.Id, //物料定义Id
                   viewModel.SelectedMaterial.Name, //物料名称
                   viewModel.SelectedMaterial.Number,//物料编号
                   viewModel.materialLotId, //物料批次Id
                   viewModel.ProductionBatchNo, //物料批次
                   viewModel.SelectedSupplier?.Id,//供应商Id
                   viewModel.SelectedSupplier?.Name,//供应商名称
                   viewModel.ProducedDate, //生产日期
                   viewModel.GuaranteePeriod,//保质期
                   viewModel.ExpiredDate, //过期日期
                   viewModel.Specification,//规格
                   viewModel.Quantity, //数量
                   viewModel.Sort,//排序
                   viewModel.Description, //描述
                   viewModel.SelectedMaterialSourceType,
                   viewModel.ReceptionDate,
                   viewModel.SelectedMaterial.StandardUnitNo);
            }
        }
        #endregion

        #region 加载储存位置
        /// <summary>
        /// 加载储存位置
        /// </summary>
        public async void LoadStorageLocation()
        {
            this.Busy();

            await this.ReloadStorageLocation();

            this.Idle();
        }
        #endregion

        #region 提交 —— async void Submit()
        /// <summary>
        /// 提交
        /// </summary>
        public async void Submit()
        {
            #region # 验证
            if (DetailParams.Count == 0)
            {
                MessageBox.Show("入库明细不能为空，至少需要一条数据！", "警告", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
            #endregion
            List<StockInOrderDetailParam> StockInOrderDetailParams = new List<StockInOrderDetailParam>();
            foreach (var detailParam in DetailParams)
            {
                MaterialLotParam materialLotParam = new MaterialLotParam();
                StockInOrderDetailParam stockInOrderDetailParam = new StockInOrderDetailParam();
                stockInOrderDetailParam.materialId = detailParam.MaterialId.Value;
                stockInOrderDetailParam.materialLotId = detailParam.MaterialLotId;
                stockInOrderDetailParam.quantity = detailParam.Quantity.Value;
                stockInOrderDetailParam.sort = detailParam.Sort;
                stockInOrderDetailParam.description = detailParam.Description;
                if (detailParam.SupplierId != null)
                {
                    materialLotParam.supplierId = detailParam.SupplierId.Value;
                    materialLotParam.productionBatchNo = detailParam.ProductionBatchNo;
                    materialLotParam.producedDate = detailParam.ProducedDate.Value;
                    materialLotParam.guaranteePeriod = detailParam.GuaranteePeriod.Value;
                    materialLotParam.expiredDate = detailParam.ExpiredDate.Value;
                    materialLotParam.receptionDate = detailParam.ReceptionDate.Value;
                    materialLotParam.specification = detailParam.Specification;
                    materialLotParam.materialSourceType = detailParam.MaterialSourceType.Value;
                    stockInOrderDetailParam.materialLotParam = materialLotParam;
                }
                StockInOrderDetailParams.Add(stockInOrderDetailParam);
            }

            this.Busy();
            //创建入库单据
            await Task.Run(() => this._iStockOrderContract.Channel.UpdateStockInOrder(
                this._stockInOrderInfo.Id,//入库单Id
                SelectedStorageLocationType.Value,//目标储存位置类型
                SelectedStorageLocation.Id.ToString(),//目标储存位置Id
                SelectedStorageLocation.Name,//目标储存位置名称
                FacilityId,//工厂模型Id
                Description,//描述
                StockInOrderDetailParams));
            await base.TryCloseAsync(true);
            this.Idle();
        }
        #endregion

        #region 删除单据明细
        /// <summary>
        /// 删除单据明细
        /// </summary>
        public async void RemoveStockIn(StockInOrderDetailNm stockInOrderDetailNm)
        {
            this.Busy();
            //清除单据明细缓存
            DetailParams.Remove(stockInOrderDetailNm);
            this.Idle();
        }
        #endregion

        #region 创建单据明细 —— async Task CreateDetailParam()
        /// <summary>
        /// 创建单据明细
        /// </summary>
        /// <param name="materialId">物料定义Id</param>
        /// <param name="materialName">物料名称</param>
        /// <param name="materialNo">物料编号</param>
        /// <param name="materialLotId">物料批次Id</param>
        /// <param name="ProductionBatchNo">物料批次</param>
        /// <param name="supplierId">供应商Id</param>
        /// <param name="SupplierName">供应商名称</param>
        /// <param name="ProducedDate">生产日期</param>
        /// <param name="GuaranteePeriod">保质期</param>
        /// <param name="ExpiredDate">过期日期</param>
        /// <param name="Specification">规格</param>
        /// <param name="InitialQuantity">数量</param>
        /// <param name="sort">排序</param>
        /// <param name="description">描述</param>
        /// <param name="materialSourceType">物料来源</param>
        public void CreateDetailParam(Guid? materialId, string materialName, string materialNo, Guid? materialLotId, string ProductionBatchNo, Guid? supplierId, string SupplierName, DateTime? ProducedDate, int GuaranteePeriod, DateTime? ExpiredDate, string Specification, decimal InitialQuantity, int sort, string description, MaterialSourceType? materialSourceType, DateTime? receptionDate, string standardUnitNo)
        {
            this.Busy();
            //添加入库单明细参数模型
            DetailParams.Add(new StockInOrderDetailNm(
                materialId,
                materialName,
                materialNo,
                materialLotId,
                InitialQuantity,
                sort,
                description,
                null,
                supplierId,
                SupplierName,
                ProductionBatchNo,
                ProducedDate,
                TimeSpan.FromDays(GuaranteePeriod),
                ExpiredDate,
                receptionDate,
                Specification,
                materialSourceType,
                null,
                null,
                false,
                false,
                null,
                null,
                standardUnitNo
                ));
            this.Idle();
        }
        #endregion

        //Private
        #region 加载储存位置列表 —— async Task ReloadStorageLocation()
        /// <summary>
        /// 加载储存位置列表
        /// </summary>
        public async Task ReloadStorageLocation()
        {
            #region # 验证

            if (this.SelectedStorageLocationType == null || this.SelectedStorageLocationType == null)
            {
                this.StorageLocations = new ObservableCollection<IdentiferNameNm>();
                return;
            }
            #endregion

            //显示隐藏库位列表
            this.StorageLocationComboBoxVisibility = Visibility.Visible;
            this.StorageLocationTextVisibility = Visibility.Collapsed;
            switch (SelectedStorageLocationType)
            {
                case StorageLocationType.ProductionDomain://生产域
                    IEnumerable<IAppService.DTOs.Outputs.FoundationContext.FacilityInfo> Facilities = await Task.Run(() =>
                    this._iFoundationContract.Channel.GetFacilities(
                        null,//关键字
                        null,//工厂模型层次
                        FacilityType.ProductionDomain,//工厂模型类型
                        null)//上级节点Id
                    );
                    IEnumerable<IdentiferNameNm> Facilitiemodels = Facilities.Select(x => x.ToIdentiferName());
                    StorageLocations = new ObservableCollection<IdentiferNameNm>(Facilitiemodels);
                    break;
                case StorageLocationType.BusinessDomain://业务域
                    Facilities = await Task.Run(() =>
                    this._iFoundationContract.Channel.GetFacilities(
                        null,//关键字
                        null,//工厂模型层次
                        FacilityType.BusinessDomain,//工厂模型类型
                        null)//上级节点Id
                    );
                    Facilitiemodels = Facilities.Select(x => x.ToIdentiferName());
                    StorageLocations = new ObservableCollection<IdentiferNameNm>(Facilitiemodels);
                    break;
                case StorageLocationType.StorageDomain://储存域
                    Facilities = await Task.Run(() =>
                   this._iFoundationContract.Channel.GetFacilities(
                      null,//关键字
                      null,//工厂模型层次
                      FacilityType.StorageDomain,//工厂模型类型
                      null)//上级节点Id
                  );
                    Facilitiemodels = Facilities.Select(x => x.ToIdentiferName());
                    StorageLocations = new ObservableCollection<IdentiferNameNm>(Facilitiemodels);
                    break;
                case StorageLocationType.Person://人员
                    PageModel<PersonInfo> Persons = await Task.Run(() =>
                      this._iResourceContract.Channel.GetPersonsByPage(
                         null,//关键字
                         FacilityId,//工厂模型Id
                         null,//人员类Id
                         1,
                         int.MaxValue)//上级节点Id
                   );
                    IEnumerable<IdentiferNameNm> Personsmodels = Persons.Datas.Select(x => x.ToIdentiferName());
                    StorageLocations = new ObservableCollection<IdentiferNameNm>(Personsmodels);
                    break;
                case StorageLocationType.Team://班组
                    PageModel<TeamInfo> Teams = await Task.Run(() =>
                     this._iResourceContract.Channel.GetTeamsByPage(
                        null,//关键字
                        FacilityId,//工厂模型Id
                        1,
                        int.MaxValue)//上级节点Id
                  );
                    IEnumerable<IdentiferNameNm> TeamModels = Teams.Datas.Select(x => x.ToIdentiferName());
                    StorageLocations = new ObservableCollection<IdentiferNameNm>(TeamModels);
                    break;
                case StorageLocationType.Customer://客户
                    PageModel<EnterpriseInfo> Enterprises = await Task.Run(() =>
                    this._iResourceContract.Channel.GetEnterprisesByPage(
                       null,//关键字
                       EnterpriseType.Customer,//工厂模型Id
                       null,
                       1,
                       int.MaxValue)//上级节点Id
                 );
                    IEnumerable<IdentiferNameNm> EnterpriseModels = Enterprises.Datas.Select(x => x.ToIdentiferName());
                    StorageLocations = new ObservableCollection<IdentiferNameNm>(EnterpriseModels);
                    break;
                case StorageLocationType.Supplier://供应商
                    Enterprises = await Task.Run(() =>
                   this._iResourceContract.Channel.GetEnterprisesByPage(
                      null,//关键字
                      EnterpriseType.Supplier,//工厂模型Id
                      null,
                      1,
                      int.MaxValue)//上级节点Id
                );
                    EnterpriseModels = Enterprises.Datas.Select(x => x.ToIdentiferName());
                    StorageLocations = new ObservableCollection<IdentiferNameNm>(EnterpriseModels);
                    break;
                case StorageLocationType.Description://描述
                    StorageLocationComboBoxVisibility = Visibility.Collapsed;
                    StorageLocationTextVisibility = Visibility.Visible;
                    break;
            }
        }
        #endregion

        #endregion
    }
}
